package gops

import (
	"errors"
	"fmt"
	"os/exec"
	"time"
)

// CommandExec 为要执行的shell命令 timeout 为超时时间
func CommandExec(command string, timeout ...int) (string, error) {
	// go执行shell命令方法,支持超时
	const defaultTimeout = 30
	execTimeout := defaultTimeout
	if len(timeout) > 0 {
		execTimeout = timeout[0]
	}

	cmd := exec.Command("sh", "-c", command)

	outChan := make(chan string)
	errChan := make(chan error)

	go func() {
		result, err := cmd.CombinedOutput()
		if err != nil {
			errChan <- fmt.Errorf("执行 %s 报错了，请查看 %w", command, err)
			return
		}
		outChan <- string(result)
	}()
	// 这段代码是一个Go语言的select语句,它用于处理命令执行超时、成功输出和错误输出的情况。select语句会等待多个通道（channel）的操作，然后根据哪个通道先收到数据来执行对应的代码块。
	// select 语句会阻塞当前 Goroutine，直到其中一个 case 中的通道操作完成
	select {
	case <-time.After(time.Duration(execTimeout) * time.Second):
		if err := cmd.Process.Kill(); err != nil {
			return "", fmt.Errorf("命令执行超时，并且无法终止进程：%w", err)
		}
		return "", errors.New(fmt.Sprintf("%s 执行超时%ds", command, execTimeout))
	case output := <-outChan:
		return output, nil
	case err := <-errChan:
		return "", err
	}
}
